package com.jh.user.pojo.freeQuick;

import cn.jh.common.pay.utils.PayBarMerchant;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.base.MoreObjects;
import com.google.common.collect.Maps;

import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @author Yichuan
 * @version 1.0
 */
public class MerchantRateDTO implements Serializable {

    private static final long serialVersionUID = -8881538246891982887L;

    private Long id;
    private String merchantId;
    private String merchantNo;
    private String channelName;
    private String channelCode;
    private BigDecimal rate;
    private BigDecimal debitRate;
    private BigDecimal creditRate;
    private BigDecimal withdrawRate;
    private BigDecimal withdrawPoundage;
    private BigDecimal extraFee;
    private LocalDateTime createAt;
    private LocalDateTime updateAt;

    @JsonCreator
    public MerchantRateDTO(@JsonProperty("id") Long id, @JsonProperty("merchantId") String merchantId,
                           @JsonProperty("merchantNo") String merchantNo, @JsonProperty("channelName") String channelName,
                           @JsonProperty("channelCode") String channelCode, @JsonProperty("rate") BigDecimal rate,
                           @JsonProperty("debitRate") BigDecimal debitRate, @JsonProperty("creditRate") BigDecimal creditRate,
                           @JsonProperty("withdrawRate") BigDecimal withdrawRate, @JsonProperty("withdrawPoundage") BigDecimal withdrawPoundage,
                           @JsonProperty("extraFee") BigDecimal extraFee,
                           @JsonProperty("createAt") LocalDateTime createAt,
                           @JsonProperty("updateAt") LocalDateTime updateAt) {
        this.id = id;
        this.merchantId = merchantId;
        this.merchantNo = merchantNo;
        this.channelName = channelName;
        this.channelCode = channelCode;
        this.rate = rate;
        this.debitRate = debitRate;
        this.creditRate = creditRate;
        this.withdrawRate = withdrawRate;
        this.withdrawPoundage = withdrawPoundage;
        this.extraFee = extraFee;
        this.createAt = createAt;
        this.updateAt = updateAt;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getMerchantId() {
        return merchantId;
    }

    public void setMerchantId(String merchantId) {
        this.merchantId = merchantId;
    }

    public String getMerchantNo() {
        return merchantNo;
    }

    public void setMerchantNo(String merchantNo) {
        this.merchantNo = merchantNo;
    }

    public String getChannelName() {
        return channelName;
    }

    public void setChannelName(String channelName) {
        this.channelName = channelName;
    }

    public String getChannelCode() {
        return channelCode;
    }

    public void setChannelCode(String channelCode) {
        this.channelCode = channelCode;
    }

    public BigDecimal getRate() {
        return rate;
    }

    public void setRate(BigDecimal rate) {
        this.rate = rate;
    }

    public BigDecimal getDebitRate() {
        return debitRate;
    }

    public void setDebitRate(BigDecimal debitRate) {
        this.debitRate = debitRate;
    }

    public BigDecimal getCreditRate() {
        return creditRate;
    }

    public void setCreditRate(BigDecimal creditRate) {
        this.creditRate = creditRate;
    }

    public BigDecimal getWithdrawRate() {
        return withdrawRate;
    }

    public void setWithdrawRate(BigDecimal withdrawRate) {
        this.withdrawRate = withdrawRate;
    }

    public BigDecimal getWithdrawPoundage() {
        return withdrawPoundage;
    }

    public void setWithdrawPoundage(BigDecimal withdrawPoundage) {
        this.withdrawPoundage = withdrawPoundage;
    }

    public BigDecimal getExtraFee() {
        return extraFee;
    }

    public void setExtraFee(BigDecimal extraFee) {
        this.extraFee = extraFee;
    }

    public LocalDateTime getCreateAt() {
        return createAt;
    }

    public void setCreateAt(LocalDateTime createAt) {
        this.createAt = createAt;
    }

    public LocalDateTime getUpdateAt() {
        return updateAt;
    }

    public void setUpdateAt(LocalDateTime updateAt) {
        this.updateAt = updateAt;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof MerchantRateDTO)) return false;
        MerchantRateDTO that = (MerchantRateDTO) o;
        return getId().equals(that.getId()) &&
                Objects.equals(getMerchantId(), that.getMerchantId()) &&
                Objects.equals(getMerchantNo(), that.getMerchantNo()) &&
                Objects.equals(getChannelName(), that.getChannelName()) &&
                Objects.equals(getChannelCode(), that.getChannelCode()) &&
                Objects.equals(getRate(), that.getRate()) &&
                Objects.equals(getDebitRate(), that.getDebitRate()) &&
                Objects.equals(getCreditRate(), that.getCreditRate()) &&
                Objects.equals(getWithdrawRate(), that.getWithdrawRate()) &&
                Objects.equals(getWithdrawPoundage(), that.getWithdrawPoundage()) &&
                Objects.equals(getExtraFee(), that.getExtraFee()) &&
                Objects.equals(getCreateAt(), that.getCreateAt()) &&
                Objects.equals(getUpdateAt(), that.getUpdateAt());
    }

    @Override
    public int hashCode() {
        return Objects.hash(getId(), getMerchantId(), getMerchantNo(), getChannelName(),
                getChannelCode(), getRate(), getDebitRate(), getCreditRate(), getWithdrawRate(),
                getWithdrawPoundage(), getExtraFee(), getCreateAt(), getUpdateAt());
    }

    @Override
    public String toString() {
        return MoreObjects.toStringHelper(this)
                .add("id", id)
                .add("merchantId", merchantId)
                .add("merchantNo", merchantNo)
                .add("channelName", channelName)
                .add("channelCode", channelCode)
                .add("rate", rate)
                .add("debitRate", debitRate)
                .add("creditRate", creditRate)
                .add("withdrawRate", withdrawRate)
                .add("withdrawPoundage", withdrawPoundage)
                .add("extraFee", extraFee)
                .add("createAt", createAt)
                .add("updateAt", updateAt)
                .toString();
    }

    public static MerchantRateDTO transform(PayBarMerchant merchant, ChannelCode smartChannelCode) {
        if (merchant.getCreditRate() == null || merchant.getDebitRate() == null) {
            return null;
        }
        return new MerchantRateDTO(null, merchant.getMerchantId(), merchant.getMerchantNo(),
                smartChannelCode.getDesc(), smartChannelCode.getValue(), null, merchant.getDebitRate(),
                merchant.getCreditRate(), merchant.getWithdrawDepositRate(), merchant.getWithdrawDepositSingleFee(),
                merchant.getExtraRate(), null, null);
    }

    public static MerchantRateDTO first(List<MerchantRateDTO> rateList) {
        ChannelCode channelCode;
        Map<Integer, MerchantRateDTO> rateMap = Maps.newHashMap();
        Integer ordinal = null;
        for (MerchantRateDTO dto: rateList) {
            channelCode = ChannelCode.of(dto.getChannelCode());

            if (channelCode == null) continue;

            int idx = channelCode.ordinal();
            rateMap.put(idx, dto);
            if (ordinal == null || idx < ordinal) {
                ordinal = idx;
            }
        }
        return rateMap.get(ordinal);
    }
}
